/**
 * Project Name:cats-core-impl
 * File Name:BaseSpecification.java
 * Package Name:com.catsic.core.base.specification
 * Date:2014年4月17日下午2:30:03
 * Copyright (c) 2014, oa.catsic.com All Rights Reserved.
 */

package com.catsic.base.specification;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.jpa.domain.Specification;

import com.catsic.base.conditon.Condition;

/**
 * ClassName: BaseSpec Description: 动态查询基础类 date: 2014年4月17日 下午2:30:03
 * author: yangyd
 */
public abstract class BaseSpec<T> implements Specification<T>{
	
	/**
	 * 日志
	 */
	public static Logger logger = LoggerFactory.getLogger(BaseSpec.class);
	
	/**
	 *是否默认排序 
	 */
	private boolean is_default_sort;
	
	private static final boolean DEFAULT_DIRECTION = false;
	
	/**
	 * 查询条件
	 */
	private Condition condition;
	
	/**
	 * @param condition 查询条件
	 */
	public BaseSpec(Condition condition,boolean is_default_sort){
		this.condition = condition;
		this.is_default_sort = is_default_sort;
	}
	
	/**
	 * @param condition 查询条件
	 */
	public BaseSpec(Condition condition){
		this.condition = condition;
		this.is_default_sort = DEFAULT_DIRECTION;
	}
	
	public boolean isIs_default_sort() {
		return is_default_sort;
	}

	public void setIs_default_sort(boolean is_default_sort) {
		this.is_default_sort = is_default_sort;
	}

	/**
	 * @see org.springframework.data.jpa.domain.Specification#toPredicate(javax.persistence.criteria.Root, javax.persistence.criteria.CriteriaQuery, javax.persistence.criteria.CriteriaBuilder)
	 */
	@Override
	public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
		
		List<Predicate> predicates = new ArrayList<Predicate>();
        List<Order> orders = new ArrayList<Order>();

        QueryWraper<T> queryWraper = new QueryWraper<T>(root, cb, predicates, orders);
        addCondition(queryWraper);
        if(is_default_sort)
        	addOrder(queryWraper);

        query.orderBy(queryWraper.getOrders());
		return cb.and(predicates.toArray(new Predicate[predicates.size()]));
	}

    protected void addOrder(QueryWraper<T> queryWraper) {
        queryWraper.addOrder(queryWraper.getCb().desc(queryWraper.getRoot().get("createTime")));
    }

    /**
	 * 增加查询条件，各子类自行实现相应实体的查询逻辑
	 * @param queryWraper
	 */
	protected abstract void addCondition(QueryWraper<T> queryWraper);

	/**
	 * 向查询中添加包含(like)条件
	 * @param queryWraper 
	 * @param field 指出要向哪个字段添加包含(like)条件
	 */
	protected final void addLikeCondition(QueryWraper<T> queryWraper, String field) {
		String value = null;
		try {
			value = BeanUtils.getProperty(getCondition(), field);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
		
		addLikeCondition(queryWraper, field, value);
	}
	
	protected void addLikeCondition(QueryWraper<T> queryWraper, String path, String value){
		if(StringUtils.isNotBlank(value)){
			Path<String> fieldPath = queryWraper.getRoot().get(path);
			queryWraper.getPredicates().add(queryWraper.getCb().like( fieldPath, "%"+value+"%" ));
		}
	}
	
	protected void addLikeCondition(QueryWraper<T> queryWraper, Path<?> expression, String value){
		if(StringUtils.isNotBlank(value)){
			queryWraper.getPredicates().add(queryWraper.getCb().like(expression.as(String.class), "%" + value + "%" ));
		}
	}
	
	/**
	 * 前缀模糊查询
	 * @param queryWraper
	 * @param expression
	 * @param value
	 */
	protected void addLikeConditionPrefix(QueryWraper<T> queryWraper, Path<?> expression, String value){
		if(StringUtils.isNotBlank(value)){
			queryWraper.getPredicates().add(queryWraper.getCb().like(expression.as(String.class), "%" + value ));
		}
	}
	
	/**
	 * 后缀模糊查询
	 * @param queryWraper
	 * @param expression
	 * @param value
	 */
	protected void addLikeConditionSuffix(QueryWraper<T> queryWraper, Path<?> expression, String value){
		if(StringUtils.isNotBlank(value)){
			queryWraper.getPredicates().add(queryWraper.getCb().like(expression.as(String.class), value + "%"));
		}
	}
	
	/**
	 * 向查询中添加等于(=)条件
	 * @param queryWraper
	 * @param field 指出要向哪个字段添加 等于(=) 条件
	 */
	protected final void addEqualCondition(QueryWraper<T> queryWraper, String field) {
		Object value = null;
		
		try {
			value = PropertyUtils.getProperty(getCondition(), field);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
		
		addEqualCondition(queryWraper, queryWraper.getRoot().get(field), value);
	}
	
	/**
	 * 向查询中添加不等于(!=)条件
	 * @param queryWraper
	 * @param field 指出要向哪个字段添加 !等于(!=) 条件
	 */
	protected final void addNotEqualCondition(QueryWraper<T> queryWraper, String field) {
		Object value = null;
		
		try {
			value = PropertyUtils.getProperty(getCondition(), field);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
		
		addNotEqualCondition(queryWraper, queryWraper.getRoot().get(field), value);
	}

	protected void addEqualCondition(QueryWraper<T> queryWraper,
                                     Path<?> expression, Object value) {
		if(value != null){
			queryWraper.getPredicates().add(queryWraper.getCb().equal(expression, value));
		}
	}
	
	protected void addNotEqualCondition(QueryWraper<T> queryWraper,
            Path<?> expression, Object value) {
		if(value != null){
			queryWraper.getPredicates().add(queryWraper.getCb().notEqual(expression, value));
		}
	}

    protected void addInCondition(QueryWraper<T> queryWraper, String path, Object... values){
        if(ArrayUtils.isNotEmpty(values)){
            queryWraper.addPredicate(queryWraper.getRoot().get(path).in(values));
        }
    }

    protected void addInCondition(QueryWraper<T> queryWraper, Path<?> expression, Collection<?> values){
        if(CollectionUtils.isNotEmpty(values)){
            queryWraper.addPredicate(expression.in(values));
        }
    }
    
    protected void addInCondition(QueryWraper<T> queryWraper, Path<?> expression, Expression<?> values){
        queryWraper.addPredicate(expression.in(values));
    }
    
    protected void addInCondition(QueryWraper<T> queryWraper, String path, Collection<?> values){
        if(CollectionUtils.isNotEmpty(values)){
            queryWraper.addPredicate(queryWraper.getRoot().get(path).in(values));
        }
    }

    protected void addStartWithCondition(QueryWraper<T> queryWraper, String path, String value) {
        if(StringUtils.isNotBlank(value)){
            String [] paths = StringUtils.split(path, ".");

            Path<?> root = queryWraper.getRoot();
            int i=0;
            for(; i<paths.length -1; i++){
                root = root.get(paths[i]);
            }
            Path<String> areaPath = root.get(paths[i]);
            queryWraper.addPredicate(queryWraper.getCb().like(areaPath, value + "%"));
        }
    }

	/**
	 * @return the condition
	 */
	public Condition getCondition() {
		return condition;
	}

	/**
	 * @param condition the condition to set
	 */
	public void setCondition(Condition condition) {
		this.condition = condition;
	}

}
